Back to Contents        Previous        Next







36. Dr Wimp’s ‘Elixirs’


The main aim of Dr Wimp is to provide a comprehensive flexible and integrated set of facilities to allow the user to build Wimp applications easily and without many restrictions. Consequently the vast majority of user- and wimp-functions address items which are of general applicability and might therefore be used in a very wide range of applications.

However, from time to time, a way of meeting a more specific programming need presents itself and, where practicable, it seems useful to make these solutions available to users to add to a particular application as and if they are needed - rather than to add them as permanent parts of the skeleton !RunImage and/or DrWimp Library.

These optional additions are called ‘Elixirs’ - because they aim solely to ‘cure’ a particular problem!

Elixir_01 - Redrawing long scrolling lists
If you have a long list of text lines (to be plotted directly to a window rather than using stacked icons to show the text) the window will need to be much larger in height than the screen. i.e. a vertically scrolling window is needed to show the whole list.
When the window is scrolled the ‘redraw’ process is used to update the list lines in sympathy with the scroll position.
It soon becomes obvious that if you seek to redraw the whole list each time a scroll occurs you will find that your usual desktop operations are very seriously affected - purely because of the (repeated) time it takes to redraw the whole list - and the same undesirable effects occur if you drag/resize etc. another window on top of this text list window.
The solution is to ensure that the redraw action constrains itself solely to those text lines which are actually going to be visible at any point in time, and this is the purpose of Elixir_01.

This Elixir consists of a matched pair of one user-function DEF and one wimp-function DEF:

PROCuser_redrawtextline(x%,y%,line%)
PROCwimp_calcredrawlines(leftmargin%,topmargin%,totallines%,
                                                                                 linespacing%)

If you want to use the elixir then both these function DEFs must be added to your !RunImage listing.

You must not alter the contents of PROCwimp_calcredrawlines(). Among other things, it calls its paired user-function PROCuser_redrawtextline()- and it is to this latter that you will need to add coding.


PROCwimp_calcredrawlines() needs to be called from within PROCuser_redraw() when the list window needs updating - merely ensuring that its parameters reflect your choices, as follows:

leftmargin%
- (OS units) the horizontal distance from the left edge of the list window to the start of the text line. Normally a positive value but can be negative if required.

topmargin%
- (OS units) the vertical distance from the top of the list window to the top of the area in which the list is displayed. Normally a positive value but can be negative if required. Typically used to provide space for a superimposed non-scrolling pane at the top of the list, so that the list can ‘scroll under’ the pane without hiding the first line when the scroll is at zero.

totallines%
- the total number of text lines in the list.

linespacing%
- (OS units) the vertical spacing between list lines. (Note also that the first line of the list will be plotted at this value below the value of
topmargin%
, because the text-plotting functions use the bottom of the text as the y-value reference.)

As indicated earlier, you will need to add your specific code to:

DEF PROCuser_redrawtextline(x%,y%,line%)
and the needs are very simple indeed.

All you need to do is add the code to plot the text of one line using the passed parameters:

x%
- actual plotting x-position of line of text (in screen OS values)
y%
- actual plotting y-position of line of text (in screen OS values)
line%
- the number of the text line to plot.

Note that the x/y values are in screen OS units so that you need to use the direct screen text plotting functions rather than the ‘window’ text plotting functions.

To maintain good speed, it is normally best to store the list of text lines in an array, which needs to be set up separately.

A typical complete coding might be as simple as:

         In the main redraw user-function:

DEF PROCuser_redraw(window%,minx%,miny%,maxx%,maxy%,
                                                                                          printing%,page%)
CASE window% OF
WHEN listwindow%
PROCwimp_calcredrawlines(leftmargin%,topmargin%,listlength%
                                                                                                   linespacing%)
ENDCASE
ENDPROC

         plus:

DEF PROCuser_redrawtextline(x%,y%,line%)
PROCwimp_plottexth(text$(line%),listfont%,x%,y%,0,0,0
                                                                                                   255,255,255,0)
ENDPROC

In the Examples folder there is an example application called !Scroll to demonstrate Elixir_01.



Elixir_02 - Copying a dragged icon
Dr Wimp has facilities to manage the dragging of ordinary icons - provided they have been defined as ‘draggable’ - and it is for the programmer to decide what should happen (if anything) when dragging occurs. (This Elixir does not work for icons of button type 14 - ’Write/Click/Drag’)

One of the popular requirements might be to copy the dragged icon to the place where the drag ends, perhaps ending up with two identical icons or perhaps deleting the original icon to give the effect of moving the icon from one place to the other. Elixir _02 exists solely for this purpose.

The elixir consists of just one wimp-function DEF:

FNwimp_copydraggedicon(startwindow%,dragicon%,dragboxminx%, dragboxminy%,dragboxmaxx%,dragboxmaxy%,endwindow%, delete%)

and it is designed to be used only in DEF PROCuser_endicondrag() with which it shares all but one of its parameters - so these can be copied through.

The exception is the final parameter delete% which determines whether or not the original icon (i.e. the one which was dragged) is to be deleted in the operation.

If delete% is set to 0 then no deletion will occur and the dragged icon will remain in its original position with a copy being created at the end-of-drag position. If delete% is set to 1 then the dragged icon will be deleted from its original position - giving the effect that it has been moved from its start position to its end-of-drag position.

In either case, the new (copy) icon will be created as part of the window definition of the window in which it appears. It will have its own icon number (the lowest available, see later also) and can then be treated as any other icon defined in the window e.g. wimp-functions such as PROCwimp_puticontext() etc. can be applied to it.

Commonly, the programmer will want the icon copying to take place only within the window from where the dragging starts - and in this case endwindow% will be the same as startwindow%. It is, however, perfectly OK to copy the icon into another open window - provided that the other window is a window of the same application.

Finally, if the copying is confined within its own window and you choose to set delete% to 1, then the ‘moved’ icon will take on the same icon number as the original icon (now deleted) - as long as you ensure that there are no gaps in the icon numbering of your initial definition of the window.


Elixir_03 - Constructing a custom sprite
There are some occasions when ‘user graphics/text’ are sufficiently long-winded to make them inconvenient for a redraw window, perhaps because the graphic up-dating time becomes very evident when the window is moved/scrolled etc. For instance, displaying a graph could fall into this category.

In such cases, it is often practical to plot the graphics/text to the ‘canvas’ of a large blank sprite and then display the sprite using Dr Wimp’s normal sprite-plotting functions. The main advantage of this method is that redraw window updating is ‘instantaneous’ (in human terms, anyway). Another advantage is the fact that ordinary Basic VDU/PLOT-type commands can be used for the graphics drawing.

Elixit_03 exists solely to help with this sprite-building process.

The elixir comprises a small suite of function DEFs:

FNwimp_buildsprite(spritename$,sprwidth%,sprheight%)
PROCwimp_plotinsprite(spritearea%,spritename$,sprwidth%, sprheight%)
PROCuser_spritegraphics(spritearea%,spritename$,sprwidth%, sprheight%)
PROCwimp_setdrawspritegraphiccolour(colour%)
PROCwimp_writedrawspritetext(text$,fonth%,spritex%,spritey%, foreground%,background%)

(There is also an ‘internal’ function DEF FNwint_setupspritearea() in the suite. This needs to be copied into your !RunImage with the above functions but it is not for ‘programmer access’ !)

To use this elixir - after having copied the whole suite to your !RunImage - you need to make a single call to FNwimp_buildsprite() at the appropriate place and place your graphics/text needs in DEF PROCuser_spritegraphics(). The latter returns the handle of the resulting sprite area which can then be used in the standard wimp-functions to render the sprite (probably within DEF PROCuser_redraw() ) and/or to print it. (See Sections 2.20 and 2.25).

The call to FNwimp_buildsprite(spritename$,sprwidth%,sprheight%) is simple: spritename$ is your chosen name for the sprite e.g. “MySprite”, whilst sprwidth% and sprheight% are your required width and height for the sprite - in OS units.

In effect, this call initially defines a blank rectangular sprite ‘canvas’ of your chosen size - which will start with a default white background. It then goes on to make a call to PROCwimp_plotinsprite() - which is the wimp-function which automatically calls PROCuser_spritegraphics(). (The reason for making PROCwimp_plotinsprite() separate will become clear later.)

It is usually best to place the single call to FNwimp_buildsprite() within DEF PROCuser_initialise. However, this is not essential.

The use of PROCuser_spritegraphics() is best explained with a simple example:

DEF PROCuser_spritegraphics(spritearea%,spritename$, sprwidth%,sprheight%)
MOVE 50,50
PLOT 21,400,300
RECTANGLE 100,100,200,300
ENDPROC

This sequence of ordinary Basic VDU/PLOT-type graphic commands will (using the default plotting colour of Black) draw a dotted line from the point 50,50 to the point 400,300 on the default (White) background of the blank sprite - and then will draw a rectangle of width 200 and height 300 with its bottom left corner at 100,100. All measurements in OS units.

The result would be a sprite looking something like this (assuming the chosen size of the sprite was large enough to show all the graphics drawn here):

Picture Pics/pic015.png

There would not be much point in producing a sprite for this trivial graphic and its use is merely to show the principles involved.

For greater choice Elixir_03 includes two other wimp-functions solely for use within PROCuser_spritegraphics().

The first is:
PROCwimp_setdrawspritegraphiccolour(colour%)
whose role is just to set the foreground colour of the subsequent graphic commands.

The second is:
PROCwimp_writedrawspritetext(text$,fonth%,spritex%,spritey%, foreground%,background%)
which is somewhat more comprehensive and plots user-chosen text in an outline font in anti-aliased colours starting at a chosen point in the sprite. The font handle must have already been declared in the usual Dr Wimp way.


If, in the same application, you wish to construct more than one sprite in this manner then each must be created with a single call to FNwimp_buildsprite(). In addition, DEF FNuser_spritegraphics() needs to hold the graphic/text drawing commands for all the sprites - which is simple to arrange by using their sprite area and/or sprite names (passed in spritearea% and spritename$) to differentiate between the needs of each one.


Should you need to change the contents of the sprite after its initial creation in this way, it is again easy to do so, by calling PROCwimp_plotinsprite() independently yourself at an appropriate place - and ensuring that there are appropriate coding and constructs within DEF FNuser_spritegraphics() to respond accordingly.

(This is why PROCwimp_plotinsprite() has been made a separate wimp-function in this Elixir. Don’t forget that it is called once automatically by FNwimp_buildsprite() to enable the initial sprite contents to be drawn. Thereafter, you may call it independently whenever you wish to change the contents. Just ensure that FNuser_spritegraphics() contains the code to cope!)

The Example application !BuildSpr shows how to call PROCwimp_plotinsprite() independently in order to change a sprite contents.


If you wish to change the sprite contents completely, it helps to precede the new graphics/text plotting with the sequence:

PROCwimp_setdrawspritegraphiccolour(0):REM White **
RECTANGLE FILL 0,0,sprwidth%,sprheight%:REM Whole sprite rectangle **

which will effectively wipe the sprite ‘canvas’ clean, ready for your new plotting commands.


Finally, if you wish to save a sprite constructed using this Elixir then you can do so with PROCwimp_savesprites() - simply by using the sprite area handle returned by FNwimp_buildsprite(). This will save the sprite in a conventional sprite-file.



Elixir_04 - User-defined drag boxes
This Elixir takes advantage of the comprehensive facilities already provided in Dr Wimp for icon-dragging and contains just one wimp-function and one user-function:

PROCwimp_startuserdragbox(window%,button%,mouseworkx%, mouseworky%)

PROCuser_definedragbox(startwindow%,dragbutton%, startmouseworkx%,startmouseworky%,RETURN userboxminx%, RETURN userboxminy%,RETURN userboxmaxx%, RETURN userboxmaxy%)


Calling PROCwimp_startuserdragbox() - normally within PROCuser_mouseclick() in order to capture the current mouse position - is all that is necessary to start the drag action. window% is the window in which the drag is to start; button% is set to 4 (<select>) or 1 (<adjust>) depending on which button you want to effect the drag and mouseworkx%/mouseworky% are the starting mouse positions - in work OS units.

This wimp-function automatically calls PROCuser_definedragbox() and this is where the user defines the size and position of the drag-box. In this user-function startwindow%, dragbutton%, startmouseworkx%, startmouseworky% are self-explanatory and allow the programmer to set the starting conditions fairly comprehensively.
The four parameters userboxminx%, userboxminy%, userboxmaxx% and userboxmaxy% are all RETURN parameters - which means that the programmer can set them to the drag-box size required (different sizes under different conditions, if required). By default i.e. if the programmer leaves PROCuser_definedragbox() untouched, a drag-box of just 32 OS units - centred on the mouse position - is generated, just to show that things are working correctly. When you set your own values here, they all need to be in work OS units.

Once the drag-box has been defined the three standard user-functions used for icon-dragging come into play - but, in them, the value of dragicon% will now always be -1, to signify that no icon is involved. This provides one of the main factors used to ‘filter’ the action. Thus:

PROCuser_seticondragbounds()
is now used to limit (in screen units) the dragging area of the user-defined drag-box. As for icon-dragging, the default is the visible area of the window in which the drag is started.

PROCuser_draggingicon()
and PROCuser_endicondrag() are used, as required, to take actions during and/or at the end of dragging.

The only point needing care is to note that work OS units are used in some functions and screen OS units in others.

The Example application !Scroll has been extended to show Elixir_04 working in practice.



Elixir_05 - Managing ‘nudger’/’bump’ icons
This Elixir is a little different to others in the series in that it merely offers optional wimp-functions for a common need - that of managing ‘nudger’ or ‘bump’ icons. (The Acorn Style Guide calls these ‘adjuster arrows’.)
A typical arrangement of ‘nudger’ icons is shown in the following screenshot:

Picture Pics/pic016.png

For the purposes of this Elixir, the white icon with 100 in it will be called ‘the value icon’ and the two ‘nudgers’ to its right will be called the ‘down icon’and ‘up icon’ respectively.

You will no doubt be familiar with the operation: clicking once with <select> on the down icon will cause the value icon to decrease in value and clicking once with <select> on the up icon will cause the value icon to increase in value. If the clicking is done with the <adjust> button the actions are reversed.

The Elixir currently offers two independent wimp-functions - both intending to be used within DEF PROCuser_mouseclick.

The first is:
PROCwimp_nudgeinteger(window%,icon%,downicon%,upicon%, valueicon%,increment%,lowvalue%,highvalue%)

which is designed specifically to manage integer numbers in a simple way. It is best expalined by example. A typical use might be:

(Assume that the icon number of the ‘value icon’ is 10, the ‘downicon’ is 6 and the ‘up icon’ is 22.)

DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
WHEN main%
CASE icon% OF
WHEN 6,22
PROCwimp_nudgeinteger(window%,icon%,6,22,10,1,-5,5)
ENDCASE
ENDCASE
ENDPROC

This would increment/decrement the contents of the ‘value icon’ by 1, between the limits of -5 and +5.


The second wimp-function is:

PROCwimp_nudgereal(window%,icon%,downicon%,upicon%,valueicon%, increment,shiftincrement,lowvalue,highvalue,decplaces%)

which offers more functionality and also accepts real numbers. It is called in exactly the same way as its more simple counterpart above, except that there are now two increment values to supply and the extra parameter decplaces%.

The value placed in the parameter increment is the real number increment/decrement which is applied when the user clicks on the nudger icons with either <select> or <adjust> - whereas shiftincrement is the real number increment/decrement applied when the user clicks on the nudger icons with either <select> or <adjust> with the <shift> key held down.

As real numbers are involved it is important to control the format of the results placed in the ‘value icon’ and the parameter decplaces% specifies the format.

A typical call might then be:

PROCwimp_nudgereal(window%,icon%,6,22,10,1,0.1,-5,5,1)

Here, the normal increment/decrement is 1 - but this changes to 0.1 if the <shift> key is held down whilst the <select> or <adjust> mouse button is clicked. Again, the value can range between -5 and +5.

(If there is interest, other ‘nudger’ management options could be added to this Elixir in the future.)

Elixir_06 - Saving/retrieving window positions
Many applications offer the user the option of customising window positions so that, for instance, a window (or windows) always opens at a user-chosen position (and sometimes also visible size/scrolls).
In addition, the programmer often has a need to ensure that large windows do not open ‘off the screen’ if the user happens to be operating in a ‘smaller’ screen-mode - or on a mode change whilst the application is running..
This Elixir offers a solution to these issues, with the complementary pair of wimp-functions:

PROCwimp_savewindowsettings(window%,windowname$,savedir$)
PROCwimp_getandsetwindowsettings(window%,windowname$,savedir$, hide%,warning%)

The first of these saves a text file containing the current on-screen position, visible size and scroll values of the window whose handle is window%. This window must be already loaded/created in the application, but it does not need to be open when this call is made.
The programmer needs also to specify a name string for this window in windowname$ - and it is suggested that a string version of the window handle variable is used (e.g. if the window handle variable is main%, use “main” for windowname$). This name will be used as the saved file’s leafname - but with the prefix “W” added i.e. “Wmain” will be the leaf name in the above example.
The third parameter savedir$ also needs to be set, but if the programmer sets it as a null string the function will automatically save the file in <Choices$Write> within a sub-directory with the same name as the programmer has used in the first parameter of FNwimp_initialise() i.e. the application name. For example if the application name is “MyApp” then the file will be saved to the sub-directory <Choices$Write>.MyApp.
Thus, in this example, the complete saved file path will be <Choices$Write>.MyApp.Wmain.
However, there is nothing to stop the programmer from specifying any other directory in savedir$ instead. If this is done, a trailing “.” must not be included.

The saved file will be a text-file. This is a deliberate choice to make it easy to edit or, indeed, to create ‘off-line’. The format of the file is simply a set of numbers in string form and is best shown with a typical example:

354
452
600
800
0
-10
(remember to ensure that there is a <return> after the last entry):

These numbers represent, respectively:

Screen position of LH edge of window in OS units
Screen position of Bottom edge of window in OS units
Screen position of RH edge of window in OS units
Screen position of Top edge of window in OS units
Amount of x-scroll in OS units
Amount of y-scroll in OS units (normally a negative value, if not 0)


Having saved such a file, the other half of the process is to retrieve the saved values and use them to set the window state accordingly. This is done with the second wimp-function:

PROCwimp_getandsetwindowsettings(window%,windowname$,savedir$, hide%,warning%)

The first three parameters match those in the saving wimp-function described above. Obviously it is vital that you match the parameters exactly - and, again, the window must be already loaded in the application. If the file cannot be found nothing will happen - but you can choose to to get a warning of this by setting warning% to any value other than 0.
The parameter hide% enables the window to be altered to reflect the file settings without opening it. If hide% is set to 0 then the window will be opened after its state has been changed. But if hide% is set to 1 the window’s state is altered invisibly. A typical use would be to make the call with hide% set to 1 during application initiation, immediately after loading the window. This will change the window state ‘behind the scenes’ so that when subsequent user action calls for the window to be opened it will do so in its changed state - as required.

As a saved file in the right format can easily be created in a text editor, one practical idea is to create more than one file for a particular window with the intention of matching each file with a particular screen mode - which could be checked during application initiation using FNwimp_getscreenres(). The window could then be set up to correspond to the screen mode.

By the same token, windows can be re-sized automatically if the screen mode is changed whilst the application is running. The key to doing this is to use PROCuser_modechange() to set a flag to TRUE when the mode is changed and then use this flag in PROCuser_openwindow() to trigger a call to PROCwimp_getandsetwindowsettings().


Elixir_07 - Actions on multiple windows, icons and menu items


Sometimes you need to carry out the same operation on several windows or several icons or several menu items. This small suite of wimp-functions helps with this.

PROCwimp_group(handle%,type%,string$,state%)

This wimp-function allows you to enable/disable/toggle a group of icons in the same window, or to enable/disable/tick/untick a group of menu items in the same menu, or to select/de-select/hide/show a group of icons in the same window.

handle% is the window (or menu) handle.

type% determines the type of action:
type%=1 means a group of icons is to be enabled/disabled/toggled;
type%=2 means a group of menu items is to be enabled/disabled/toggled;
type%=3 means a group of icons is to be selected/de-selected/toggled.
type%=4 means a group of menu items is to be ticked/unticked/toggled;
type%=5 means a group of icons is to be hidden/shown/toggled.
string$ is a comma-separated list of the icon numbers (or menu items) to which the action is to be applied e.g. “6,17,19,1,3”. (As can be seen it does not need to be in numerical order.)
Further, a range of consecutive icon numbers (or menu items) can be included. For example, changing the value of string$ to become “6,15-19,1,3” would mean that the icon numbers (or menu items) would be 6,15,16,17,18,19,1,3

state% has the same meaning as in the corresponding wimp-functions in the main DrWimp library. For example:

state%=0
means disable (or de-select, or hide) the icons - or disable (or de-select, or untick) the menu items;
state%=1
means enable (or select, or show) the icons - or enable (or select, or tick) the menu items;
state%=2
means toggle the current state of the icon/menu item.



PROCwimp_groupwindow(string$,type%,centre%,stack%)

This wimp-function allows a group of windows to be opened/closed/redrawn.

string$ is a comma-separated list of window handles: that is, typically in the form:

STR$(handle1%)+”,”+STR$(handle2%)+”,”+STR$(handle3%) etc.

type% determines the action:
type%=1 means the group of windows will be opened
type%=2 means the group of windows will be redrawn
type%=3 means the group of windows will be closed

When type%=1 the values of centre% and stack% have the same meaning as in PROCwimp_openwindow(). (When type%=2 or 3 these values are ignored.)



FNwimp_findmenuticksstring(menu%)

FNwimp_findmenuticksnumber(menu%)

This is a pair of wimp-functions which find, for the menu whose handle is menu%, which menu items are currently ticked. Their only difference is in the way they provide the result. If menu items 2, 4 and 5 are currently ticked:

- the first wimp-function returns a comma-separated string
“2,4,5”
.
- the second returns the integer number
52
(binary number
%110100
i.e. Bits 2, 4 and 5 set). (Note that Bit 0 is always 0 and is never used.) This wimp-function can only be used with menus which have 31 menu items or less.

Elixir_08 - OLE (Object Linking and Embedding)
(Although its basic use is very simple the OLE Elixir is much larger than other Elixirs and several inter-linked directories are involved in order to give options for a full range of features. For this reason, no mention of this Elixir appears in Section 3 of this Manual and detailed documentation is held separately in the Elixir folder. The following is intended as a simple introduction only.)

OLE is the acronym given to a Wimp process whereby one application can call up another application automatically to do some work for it - and capture the results for its own purposes subsequently.
For instance, if your Dr Wimp application displays drawfiles then, with OLE, you could arrange for the displayed drawfile to be edited by !Draw and the results saved back for display by your application - all controlled within your application. In this case, your Dr Wimp application is called an OLE ‘client’ and !Draw is called the OLE ‘server’.
Similarly, if your Dr Wimp application can edit/process files of a particular file-type then it can be made into an OLE ‘server’ application, which will start-up and respond to other applications’ calls for editing of files of that file-type.

Elixir_08 provides facilities to make it very easy to turn your Dr Wimp application into an OLE client and/or an OLE server. Full details of both the client and server processes provided by this Elixir are contained in the comprehensive separate documentation included with the Elixir files - together with a fully-featured example application called !OLETest.

However, it may assist better understanding of the OLE process if an outline introduction is given here, and this is done below by constructing a ‘cut down’ OLE client called !Ollie. (The finished !Ollie ‘cut down’ application is included with the !OLETest application.)

Simple client operations
!Ollie will load a drawfile, use OLE to modify it using !Draw and then retrieve the changed drawfile.

Start by finding the completed !Ollie application with the Elixir_08 files and open the folder to locate the ‘CustomTmpl’ file and the ‘testfiles’ folder.

Then load Dr Wimp’s !Fabricate utility application - and in its main window:

a) change the ‘Application Name’ to “!Ollie”;
b) tick the option to use a custom window template file and drag in ‘CustomTmpl’ as located above. Tick the option ‘Iconbar click opens one of these windows’ and click over the ‘Name of window to open’ box to select ‘main’ (the only choice).
c) change the Info window contents as you wish;
d) tick the option to include a standard save window.
(All other settings can be left as default.)

e) Create a new customised skeleton application called !Ollie by clicking the OK button at the top right of !Fabricate’s main window - and drag the resulting save icon to wherever you wish (but NOT to the Elixir_08 location of the completed !Ollie application!)
.


With this new skeleton application, the initial programming steps are ‘housekeeping’ to ensure that the appropriate OLE Elixir functions are available to be brought into play.

The OLE Elixir is quite large and its various functions are split among several interlinked folders. It is therefore safest to keep these folder intact and to adhere strictly to the following procedure for all uses of this Elixir:

1) Display the folder containing !DrWimpOLE. Doing this will make sure !DrWimpOLE and other related folders are ‘seen’ which will automatically set a key system variable called DrWimpElixirOLE$Dir and a few other related system variables. This simple action makes it unnecessary to move the bulk of the OLE functions to your application. Instead they can be referenced as a Library, using the above system variable. The other related OLE functions will then also be linked automatically.
2)
Load the new !RunImage into your editor. Then
open the !DrWimpOLE folder and copy the contents of ‘ole-user’ to the end of your new !Ollie’s !RunImage listing. These are the few OLE user-functions to which you will, as usual, need access for developing the programming. Re-save the !RunImage.

Also, but only for our ‘cut down’ example application, copy the previously-located ‘testfiles’ folder into your new !Ollie application folder (and ensure that the Access attributes will allow both reading and writing to the enclosed drawfile).

Now everything is in place and we can start building on the new !Ollie !RunImage listing.

Add the following line to the new !RunImage after the (Line 20) LIBRARY call to the DrWimp library:

LIBRARY “<DrWimpElixirOLE$Dir>.Elixir_ole”
This effectively loads the OLE Elixir functions and gives the application access to them.

The next step is to call FNwimp_ole-init() in !Ollie’s initialisation sequence. The call is made by adding the following line to the current end of DEF PROCuser_initialise() - just before the ENDPROC:

saveblk%=FNwimp_ole_init(appname$,“”,saveblk%,FALSE,TRUE,TRUE, FALSE)

This call sets up several data blocks etc. for internal use during the OLE process. (It also sets the Dr Wimp special global variable UNUSED% to TRUE - an essential step for Elixir_08 to operate.) The detail of the parameters is available in the separate Elixir_08 documentation and also in Section 3.16 of the Dr Wimp manual, but there is no need to examine it at this introductory stage.

Next, we need to load a drawfile to be used as our OLE testbed. A suitable file is contained in the ‘testfiles’ folder we previously copied, so we need to add the following sequence to DEF PROCuser_initialise(), just after the above addition:

TestFile$=“<Ollie$Dir>.testfiles.DrawFile”
Testfilesize%=FNwimp_measurefile(TestFile$,0)
Testoledata%=FNwimp_createdynamic(Testfilesize%, 10*Testfilesize%,0,“Ollie”)
dummy%=FNwimp_loadfile(TestFile$,Testoledata%,0)
Testfiletype%=&AFF
Testfiletype$=“AFF”

You will recognise most of these lines as Dr Wimp’s standard drawfile loading sequence - in this case into a dynamic area which has been given the ability to expand up to 10 times the original file size - an arbitrary expansion capability but more than enough for this example.

(At this point, after saving the augmented !RunImage, it is worth running the new !Ollie just to check that it loads correctly and the normal infrastructure is working.)

We now need a way to kick off the OLE action and this is going to be done with a click on the drawfile icon (icon number 0) which appears in the small main window. We therefore need to make changes to DEF PROCuser_mouseclick() - and suitable new total contents are shown below:

DEF PROCuser_mouseclick(window%,icon%,button%,workx%,worky%)
CASE window% OF
         WHEN iconbar%
         REM** Click iconbar icon to open main window. **
         PROCwimp_openwindow(main%,1,-1)
         WHEN main%
         REM** Start OLE session when Icon 0 is clicked. **
         CASE icon% OF
                  WHEN 0
                  session_started%=FNwimp_start_ole_session(Testoledata%, 0,“”,main%,0,0,Testfiletype$,Testfiletype%,1,“”)
         ENDCASE
ENDCASE
ENDPROC

With this, a click on Icon 0 will call FNwimp_start_ole_session() which passes details of the drawfile loaded earlier plus the window handle etc.

If you now run the application, click on the iconbar and then click on the drawfile icon in the window, you will find that !Draw is started and the !Ollie-loaded drawfile loaded into it and displayed - ready to edit. (Note from the file-name it the !Draw window title-bar that this editable drawfile is held as a Scrap file.)
However, at the moment, any editing cannot be captured back to !Ollie, and that is our final stage.

First, a quick visit to DEF PROCuser_wimpmessage() is needed, into which we need to add:

LOCAL done%
done%=FNwimp_catch_ole_msgs(messagenumber%,block%,reasoncode%)

FNwimp_catch_ole_msgs() is a multi-purpose OLE wimp-function which responds to various OLE wimp-messages. Here, its role is to trigger actions by our application when:

a) OLE has been correctly activated (and !Draw started, if need be);
b) !Draw has modified our file;
c) the OLE session has ended.

Of these, b) is our main current concern because we need to generate code to tell our application what to do to retrieve the modified drawfile - and this is done within DEF PROCuser_ole_file-changed() which is one the ole user-functions copied to the !RunImage earlier.

In this user-function we want to save the amended drawfile back to the Ollie-created dynamic area from whence it came (which might mean increasing the dynamic area size) and also save the same result back to the originating file in the ‘testfiles’ folder. This is straightforward coding and the modified user-function becomes:

DEF PROCuser_ole_file_changed(filename$,ftype%,session_handle%, whan%,x%,y%,sendertask%,RETURN useroledata%, RETURN oledatasize%)
LOCAL newolefilesize%,dummy%,newTestoledata%
IF whan%=main% THEN
         REM** Measure ole-edited file size. **
         newolefilesize%=FNwimp_measurefile(filename$,0)
         IF newolefilesize%>0 THEN
                  IF newolefilesize%>Testfilesize% THEN
                           REM** Increase DA if need be. **
                           newTestoledata%=FNwimp_changedynamic(Testoledata%,1, newolefilesize%)
                           IF newTestoledata%<>0 THEN
                                    REM** Re-assign variables. **
                                    Testoledata%=newTestoledata%
                                    Testfilesize%=FNwimp_measuredynamic(Testoledata%)
                                    useroledata%=newTestoledata%
                                    useroledatasize%=Testfilesize%
                           ENDIF
                  ENDIF
                  REM** Re-load ole-edited file into DA. **
                  dummy%=FNwimp_loadfile(filename$,Testoledata%,0)
                  REM** Re-save ole-edited file as new test file. ** PROCwimp_savefile(TestFile$,Testoledata%,ftype%)
         ENDIF
ENDIF
ENDPROC

You should be able to follow this, with the REMs to help - bearing in mind that the filename and file-type of the edited drawfile (and other potentially useful items) are passed to you by the parameters.

As far as this ‘cut down’ OLE example is concerned, we have finished. So, save the !RunImage and run the application. When you now start the OLE process, modify the displayed drawfile and carryout an apparently normal Save action on the amended drawfile, you will find that the original version of the drawfile (in your application’s ‘testfile’ folder) will have been altered correspondingly - and the amended version also loaded into the dynamic area ready for further OLE action.

Thus, the basics of using Dr Wimp’s OLE Elixir are very simple. However, there are several other issues that would need to be done in a fully-featured application - for instance, to allow more than one OLE session (’server’ and/or client’) to be active at the same time and to safeguard against conflict with multiple scrap files. To see more on the differences needed it is easiest to compare the !RunImage listings of !Ollie and !OLETest whilst examining the separate detailed documentation for this Elixir.



---------------------------------------------



If you have an idea for an ‘elixir’ please contact the Dr Wimp author.

The best ideas come from actual users!



Top of page        Back to Contents        Previous        Next